Skip to content

fix(ui): open notes beside the player and name the API key buttons - #486

Merged
chhoumann merged 16 commits into
masterfrom
fix/final-polish
Oct 15, 2026
Merged

chhoumann merged 16 commits into
masterfrom
fix/final-polish

Conversation

@chhoumann

@chhoumann chhoumann commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

Why

Two gaps were left before 2.22.0. A screen reader announced both API key buttons in settings as "Link...", with no hint which key each is for. With PodNotes in the main area, Save as note and Open note in the Transcript panel opened the note in a new tab that hid the player. Create note and Create podcast note did the same. On a phone, a touch drag left a queue grip with the keyboard focus ring.

What changed

  • Each API key button is named by its own words and its row, for example "Link... OpenAI API key" or "Change OpenAI API key". The visible text stays in the name for voice control. The settings mock now renders Obsidian's button, and the real-app Tab walk reaches both buttons.
  • openNote opens every note PodNotes makes or finds. With the view active in the main area or a popout, it picks the leaf itself: the first visible, unpinned note in another tab group of that window, else a new split beside the view, which later notes reuse. It never uses the view's own tab group, where a new tab covers the player and a note stacked with it scrolls the player away. Otherwise Obsidian picks the leaf, as before.
  • A dragged queue grip still takes focus, so arrow keys move its episode after a click or a drag, but it shows the focus ring only once a key moves it.
  • Tidy, no behavior change: isPlaying moves beside PlayerStatus, and the view, the API and the media session share it. transcriptNote in TranscriptionService.ts is the one place that finds a transcript note, for the service, the Transcript panel and getTranscript.

Scope

  • The default transcript template keeps its # {{title}} heading. The default episode note and podcast note templates start with the same heading, so all three stay alike. Obsidian's Show inline title setting controls the second title.
  • A sidebar and a phone keep Obsidian's placement.
  • Next to a pinned note at pane width, the split leaves the player about 212 px, where its labels clip. Follow-up: a minimum width for the split, or a layout for that width.
  • createPodcastNote.ts and createFeedNote.ts were outside this unit's file list. Each changes one call, so episode and podcast notes open the same way as transcripts.

Tradeoffs

  • Deferring to getLeaf() whenever some note is beside the view still fails in a stacked tab group: Obsidian counts every stacked tab and takes the one active last, which can be the note stacked with the player. So openNote picks the leaf itself, and with several notes beside the view it takes the first, not the one active last.
  • A new tab in the view's group hides the player. A split beside the view is the one placement that always keeps it in sight.

Blast Radius

Every note PodNotes opens goes through openNote. Placement changes only while the PodNotes view is the active leaf in the main area or a popout, so a command run from an editor still opens in that editor's place. No data, settings, API or URI change.

Verification

Node 22.23.2, Obsidian 1.14.4 (isolated runner, Linux).

  • npm run lint, format:check, typecheck, build, test (2,735 tests), test:tooling (35 tests) and docs:build pass. npm run test:e2e on a fresh vault passed 225 of 225 tests in 30 files at this head.
  • The new settings and placement e2e tests fail on master's bundle (secret buttons named "Link..."; the view hidden and the note in the view's tabs) and pass here. The phone test passes on both, as intended.
  • The stacked-view unit and e2e cases fail at 7b58cda ("Back, Play and Forward after Save as note: expected false") and pass here. The touch-drag ring test fails before the grip fix and passes after; the existing arrow-key test still passes.
  • Pixel pass, master against this branch, transcript at 320, 820 and 390 in light and dark, and the settings key rows in light and dark: identical, except 65 pixels in the phone shots, which are Obsidian's open-tab counter in the mobile navbar (2 against 3 tabs from earlier runs).
Width Master This branch
820 pane Note in a new tab, player hidden Note in a split beside the player
320 sidebar Note in the main area Same
390 phone Note in its own tab Same

Mutations

Standing order 32. Each mutant was rebuilt and run against the tests named. All fail.

Mutant Fails
Secret buttons left unlabelled unit naming tests, e2e Tab walk
Named by the row only (drops "Link...") unit, e2e
Row name before the button's words unit, e2e
Render-time aria-label copy instead of aria-labelledby unit, e2e
Buttons labelled with the fields, by the row only unit, e2e
Both buttons share one id unit ("Change" vs "Link...")
Labelling before the row renders unit, e2e
openNote always defers to getLeaf() main-area, stacked, pinned and popout e2e
Defers to getLeaf() when a note is beside the view (only the same-group check added) openNote unit, stacked e2e (stacked note active last)
Notes in the view's own tab group count openNote unit, stacked e2e (controls out of the window)
Pinned notes count openNote unit, pinned-and-hidden e2e
A reused note opens without focus main-area, stacked, pinned and popout e2e
A new tab instead of a split openNote unit, main-area e2e
Split on every open, no reuse openNote unit, main-area e2e
Hidden tabs count as a note in sight pinned-and-hidden e2e
No sidebar check main-area e2e (sidebar step)
Main window leaves only (iterateRootLeaves) popout e2e
Same root only, any popout counts popout e2e (two popouts)
No phone guard phone e2e (Open note)
Episode and podcast notes left on getLeaf() main-area e2e
Save as note left on getLeaf() main-area e2e
Grip focused with the ring on press phone grip e2e
Grip not focused on press arrow-key e2e after a click
Lock screen shows "none" for an ended episode media session unit test
isPlaying drops loading player, media session and API unit tests

Size

npm run size, gzip level 9: master 102,215, this branch 102,495 (+280, 505 under the 103,000 budget). Most of it is openNote.

Docs at release

  • notes.md, Create episode notes and Create feed notes: after "PodNotes creates the note and opens it", add "With PodNotes in the main area, the note opens beside it, so the player stays in sight."
  • transcripts.md, after "PodNotes saves it as a note and opens it": add the same sentence. Where the page describes the Transcript panel's Save as note and Open note, they follow it too.
  • getting-started.md, line 44 ("PodNotes creates the note, opens it"): add the same sentence if the page shows the main-area layout.
  • No change for the API key buttons. They look the same; only their screen reader names change.
  • No change for the queue grip: its focus ring now shows only for the keyboard.

Screenshots

Master on the left, this branch on the right, right after Save as note.

820 pane:

320 sidebar:

390 phone:

The view stacked with a note, at 864 px, 7b58cda on the left, this branch on the right:

The same with a note split off beside the view, and the stacked note active last:

Note

Open notes beside the PodNotes view and label API-key buttons accessibly

  • Adds a shared note-opening helper in openNote.ts. Notes opened from PodNotes (feed, podcast, transcript) now open beside the active PodNotes view instead of replacing it. They reuse a visible, unpinned note tab in another tab group of the same window, or create a split. Phones, sidebars, and popouts keep existing behavior.
  • Gives API-key buttons in the settings tab accessible names that combine their Link/Change action with the setting-row name, in PodNotesSettingsTab.ts.
  • Consolidates the player isPlaying predicate into PlayerController and the transcript path/file lookup into TranscriptionService, replacing the deleted episodeRow predicate and getEpisodeTranscriptPath utility. Duplicate-transcription checks now use the shared lookup and report the existing file's resolved path.
  • Fixes the queue-list drag grip so a pointer drag no longer leaves a keyboard focus ring, while keyboard reordering keeps its focus ring.
  • Risk: notes opened from PodNotes now open in a new or reused tab instead of the default leaf; check openNote placement rules and the e2e placement journeys in journey-transcript.test.ts.

Macroscope summarized 0c987a1.

The settings mock rendered the secret picker as a text input, so the unit
naming test checked a control users never see. It now renders Obsidian's
Link... button, and both the unit test and the real-app Tab walk include
the OpenAI and Deepgram key buttons.
Obsidian's secret picker is a button that reads Link... or Change, so a
screen reader could not tell the OpenAI key from the Deepgram key. Each
button is now labelled by its own words and its row's name, for example
"Change OpenAI API key", so the visible text stays in the name.
In the main area, Save as note, Open note, Create note and Create podcast
note must leave the view in sight, and in a sidebar a note opens in the
main area.
With the view active in the main area and no note in sight, Obsidian opens
a note in a new tab in the view's own tab group, which hides the player.
Episode, podcast and transcript notes now open through openNote, which
splits beside the view in that case and otherwise opens where Obsidian
would. A later note reuses the split. Sidebars and phones keep their
behavior.
The view, the API and the media session each decided that a loading
episode counts as playing. isPlaying now lives beside PlayerStatus and
all three use it. A media session test pins the loading and ended states.
The panel, the service and the API each rendered the transcript path and
looked the note up. TranscriptionService.ts now exports transcriptNote,
and getEpisodeTranscriptPath folds into it. A service test pins the
refusal to transcribe an episode whose note is already there.
A popout gets the same split beside the view, which a second note reuses.
A phone keeps Obsidian's tab. Each test deletes the notes it makes.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Deploying podnotes with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0c987a1
Status: ✅  Deploy successful!
Preview URL: https://49985e59.podnotes.pages.dev
Branch Preview URL: https://fix-final-polish.podnotes.pages.dev

View logs

A stacked tab group shows every tab, so a note stacked with the PodNotes
view counted as a note in sight, and opening there scrolled the player
out of the window. The e2e placement check now measures sight by the
window, and a unit and an e2e case cover a stacked view with and without
a note beside it.
While the view is active in the main area or a popout, openNote now
picks the leaf itself: the first note in sight in another tab group of
that window, else a split beside the view. getLeaf() could take a note
stacked with the view, which scrolls the player out of sight.
…row key

On a phone, a touch drag left the grip with the keyboard focus ring. The
test drags by touch as the first input on the Queue page, then moves the
episode with an arrow key, which should show the ring.
The grip still takes focus on a press, so arrow keys move its episode
after a click or a drag, but it shows the ring only once a key moves it.
Save as note and Open note must open beside the view rather than in a
pinned note, in a unit case and in the real app.
…dden tab beside the view

In a stacked tab group, Back, Play and Forward must stay inside the
window and on top after Save as note and Open note. Beside the view, a
hidden tab behind a pinned note must be left alone too.
Only the press needs focusVisible: false. A refocus while the row moves
shows no ring on its own, so it stays as it was.
At 864 px a stack scrolled to the note leaves the player's controls out
of the window, so the controls check catches it on its own.
@chhoumann
chhoumann merged commit 53e0acb into master Oct 15, 2026
16 checks passed
@chhoumann
chhoumann deleted the fix/final-polish branch October 15, 2026 09:24
chhoumann added a commit that referenced this pull request Oct 15, 2026
Ports the Docs at release sections of #486 and #487. Notes that the
player, the Transcript panel, and the podcast menu open go beside the
PodNotes view in the main area. A file that sync replaces during a save
merges without the save notice.
chhoumann added a commit that referenced this pull request Oct 15, 2026
Since #486 a touch drag leaves no focus ring on the queue grip.
chhoumann added a commit that referenced this pull request Oct 15, 2026
* docs(transcripts): describe published transcripts and the from-audio command

* docs: port sync, private feed, capture, note, and local file changes

* docs: port player, API, template, settings, and import changes

* docs(readme): mention free transcripts from the feed

* docs: apply round 1 review fixes and move save problems to their own page

* docs: apply round 2 review fixes

* docs: apply round 3 review fixes

* docs(settings): keep the Search Podcasts section until the UI docs pass

* docs: apply round 4 review fixes

* docs: apply round 5 review fixes

* docs: apply round 6 review fixes

* docs: apply round 7 review fixes

* docs: apply round 8 review fixes

* docs: apply round 9 review fixes

* docs: apply round 10 review fixes

* docs: apply round 11 review fixes

* docs: apply round 12 review fixes

* docs: apply round 13 review fixes

* docs: apply round 14 review fixes

* docs: apply round 15 review fixes

* docs: describe the v3 view, player, and settings for 2.22.0

Rewrites the pages that described the 2.21.1 view and settings, adds a page for the player, and rewrites docs/scripts/screenshots.mjs on the verify skill's screens tooling with the fixture library. The screenshots are provisional until the final visual pass merges.

* docs: apply round 1 review fixes

Adds an Update to 2.22.0 page, fixes the loaded-episode and offline wording, makes in-page links site-absolute, and adds a phone twin for the transcript shot.

* docs: apply round 2 review fixes

Corrects what happens after importing a 2.21.1 settings file, fits alt texts to their phone crops, and crops the first-run shot.

* docs: apply round 3 review fixes

* docs: apply round 4 review fixes

* docs: describe the headset buttons as new for 2.21.1 users

* docs: describe the final v3 UI and capture the final screenshots

Applies #485's Docs at release items: Remove from Local files, Exit fullscreen, Open note in the Transcript panel, Set feed address off while offline, and the Download path warning.

* docs: apply round 5 review fixes

Name icon buttons by what a reader sees now that #485 gave them per-episode
names, split the no-transcript paragraph into a list, scope the iPhone
fullscreen sentence, and end phone note crops below the last whole block.

* docs: share the screenshot script's scene helpers

Move the seed plan, the docs' fixture library, episode notes made with
PodNotes' commands, and the instance's CDP channel out of screenshots.mjs
into scene.mjs, so the clip recorder can use them too.

* docs: record the guide clips with videos.mjs

node docs/scripts/videos.mjs records five clips in the isolated Obsidian
with real mouse and touch input and a drawn pointer, at 2x through
Electron's zoom, and writes H.264 MP4s with WebP posters and dark twins
to docs/public/videos.

* docs: show the guide clips on their pages

Getting started, Capture timestamps, Use the player, Transcribe episodes,
Use the queue and playlists, and Use private feeds each get a clip after
a sentence that says what it shows. A clip plays muted on a loop, and
readers who prefer reduced motion get its poster and controls instead.
The docs README now describes the current screenshot script.

* docs: apply the clip review fixes

Pause clips when the reader turns on reduced motion, scroll Up next in
the phone clip so the whole new queue shows, hide the drawn mouse arrow
in touch clips, keep times out of clip alt text, where the site's
directive syntax drops them, and take posters after the click ring fades.

* docs: end the queue clip on the new order and clear the feed poster

The phone clip now holds on Up next with the moved episode first, scrolls
to the last episode, and scrolls back, and the private feed's poster has
the pointer off the pasted address.

* docs: open notes beside the player and merge synced files during a save

Ports the Docs at release sections of #486 and #487. Notes that the
player, the Transcript panel, and the podcast menu open go beside the
PodNotes view in the main area. A file that sync replaces during a save
merges without the save notice.

* docs: record the queue clip without the grip's focus ring

Since #486 a touch drag leaves no focus ring on the queue grip.

* docs: say where a note opens in each layout

Round 1 review: readers could not tell where a note opens with the view
in a sidebar. One section on the notes page now covers the sidebar, the
main area or a popout, phones, and a note that opens while another tab
is active. Fix save problems and Sync now name both causes of the save
notice.

* docs: name each case of where a note opens

Round 2 review: Where a note opens now says which tab a note takes in
each layout, includes commands run from a note, and does not imply that
a capture opens the note. Getting started and the update page note the
phone exception. Sync says that a change written over between the read
and the write shows no notice.

* docs: note that 2.21.1 and 2.22.0 don't share an episode's later progress
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant